/*
 * Ax model
 * Copyright 2012 Revenco
 * Date: 2012/8/7 15:55:06
 */
__debug = false; //debug 开关

/**
 * @class Ax
 * @singleton
 */
if( !window.Ax )
    Ax =  {};
(function(Ax){
    function createXhr(){
        if (window.XMLHttpRequest) 
            return new XMLHttpRequest();
        else if (window.ActiveXObject) 
            try {
                return new ActiveXObject("Msxml2.XMLHTTP");
            } 
            catch (e) {
                try {
                    return new ActiveXObject("Microsoft.XMLHTTP");
                } 
                catch (e) {
                }
            }
    }
    
    function json2paramStr(obj){
        if (!obj) 
            return '';
        var arr = [];
        for (var k in obj) {
            var ov = obj[k], k = encodeURIComponent(k);
            var type = typeof ov;
            if (type === 'undefined') {
                arr.push(k, "=&");
            }
            else if (type != "function" && type != "object") {
                arr.push(k, "=", encodeURIComponent(ov), "&");
            }
            else if (ov instanceof Array) {
                if (ov.length) {
                    for (var i = 0, len = ov.length; i < len; i++) {
                        arr.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
                    }
                }
                else {
                    arr.push(k, "=&");
                }
            }
            else if (type === 'object') {
                // 只支持一级对象嵌套，｛"innerObj":{"o1":"x1","o2":"x2"}将生成这样的参数: innerObj[ol]=x1&innerObj[o2]=x2
                for (var kk in ov) {
                    arr.push(k, '[', kk, ']', '=', encodeURIComponent(ov[kk]), '&');
                }
            }
        }
        arr.pop();
        return arr.join("");
    }
	
    /**
	 * 底层ajax方法,一般无须直接调用该方法
     * @method ajax
     * @param {Object} param
     * <pre><code>
param是一个配置对象(json object)，其可配置项如下：
{String} url               请求目标URL
{String} method            请求方法 POST/GET
{String} encoding          发送内容的字符编码，未设置采用默认
{String} dataType          返回内容类据类型，text或json，默认为text
{String|Object} data       请求时传递的数据，可为字符串，也可为键值对
{Object} scope             可指定回调方法调用时的this对象
{String} async             是否异步，默认为异步
{Function} success         请求成功后回调方法， 响应的数据将传给该方法
{Function} failure         请求失败后回调方法， 响应的数据将传给该方法

调用示例：
Ax.ajax({ 
	url: 'http://xxxx', 
	method: 'get', 
	dataType: 'json',     //JSON模式
	success: function(r) {
		for(var i in r) 
			alert(r[i]);
	}
});
Ax.ajax({
	url: 'http://xxxx', 
	method: 'get', 
	dataType: 'text',    //文本模式
	success: function(r){ 
		alert(r); 
	}
});
Ax.ajax({url: 'http://xxxx', method: 'post', dataType: 'text', success: function(r){ alert(r); }})

     * </code></pre>
     * @return XmlHttpRequest
     */
    Ax.ajax = function(param){
        var ajax = createXhr(), url = param.url;
        if (!ajax) 
            throw "can't create ajax object!";
        param.method = param.method ? param.method.toUpperCase() : 'GET'; //请求方法默认为GET
        //添加随机字符，避免缓存
        url = url + (url.indexOf('?') >= 0 ? '&_=' : '?_=') + (+new Date());
        var ps = param.data;
        //将obj转成url param形式的字符串
        if (ps) {
            if (typeof ps === 'object') 
                ps = json2paramStr(ps);
            if (param.method === 'GET') {
                url = url + '&' + ps;
            }
        }
        param.async = param.async !== undefined ? param.async : true;
        ajax.open(param.method, url, param.async);
        if (param.method === 'POST') {
            ajax.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=' + (param.encoding ? param.encoding : ''));
        	ajax.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
		}
        ajax.onreadystatechange = function(){
            if (ajax.readyState === 4) {
                var ok = (ajax.status === 200);
                if (ok && param.success) {
                    try {
                        var data = (!param.dataType || param.dataType === 'json') ? eval("(" + ajax.responseText + ");") : ajax.responseText;
                    } 
                    catch (e) {
                        if (__debug) {
                            console && console.log('返回格式有误\n', url, '\n', ajax.responseText);
						}
                        ok = false;
                    }
                    if (ok) 
                        param.success.call(param.scope || this, data, ajax);
                }
                
                if (!ok && param.failure) {
                    param.failure.call(param.scope || this, ajax.responseText, ajax);
                }
            }
        };
        // 发送请求，如有POST data则带上
        ajax.send("POST" === param.method ? ps : undefined);
        return ajax;
    };
    
    /**
	 * 发起一个get请求	
	 * <pre><code>
调用示例：
Ax.get('http://xxxx', {'page':2, count: 20}, function(r){ alert(r); });	 </pre></code>
     * @method get 	 
     * @param {String} url
	 * @param {String|Object} data
	 * @param {Function} fn
	 * @param {Object} param
     * @return XmlHttpRequest
	 */
    /**
	 * 发起一个post请求	 
	 * <pre><code>
调用示例：
Ax.post('http://xxxx', {'page':2, count: 20}, function(r){ alert(r); });</pre></code>
     * @method post
	 * @parem {String} url
	 * @param {String|Object} data
	 * @param {Function} fn
	 * @param {Object} param
     * @return XmlHttpRequest
     */

	  
    /**
	 * 发起一个get请求,返回数据必须为JSON格式
	 * <pre><code>
调用示例：
Ax.getJSON('http://xxxx', {'page':2, count: 20}, function(r){ for(var i in r) alert(r[i]); } );</pre></code>
     * @method getJSON 
	 * @parem {String} url
	 * @param {String|Object} data
	 * @param {Function} fn
	 * @param {Object} param
     * @return XmlHttpRequest
     */
    'get post getJSON'.replace(/\w+/g, function(methodName){
        Ax[methodName] = function(url, data, fn, param){
            param = param || {};
            param.url = url;
            param.method = methodName == 'getJSON' ? 'get' : methodName;
            param.dataType = (methodName == 'getJSON' ? 'json' : !param.dataType ? 'text' : 'json');
            
            if (data && typeof data != 'function') 
                param.data = data;
            
            param.success = typeof fn == 'function' ? fn : (typeof data == 'function' ? data : undefined);
            
            return Ax.ajax(param);
        }
    });
	
    /**
	 * @event beforeSend 发送请求之前
	 * @param {Object} param
     */
	
	/**
	 * @event afterResponse 请求有响应后，不管成功 or 失败
	 * @param {Object} param
     */
})(Ax);
